Skip to content

Add begin_keywords / end_keywords with "VAMS-2023" (VAMS-2023 §10.6, Mantis 7921) - #28

Merged
sai-v-ch merged 3 commits into
OpenVAF:mobfrom
sai-v-ch:vams2023-begin-keywords
Aug 1, 2026
Merged

Add begin_keywords / end_keywords with "VAMS-2023" (VAMS-2023 §10.6, Mantis 7921)#28
sai-v-ch merged 3 commits into
OpenVAF:mobfrom
sai-v-ch:vams2023-begin-keywords

Conversation

@sai-v-ch

Copy link
Copy Markdown
Collaborator

Part of the VAMS-2023 alignment effort tracked in #19.

Summary

VAMS-2023 §10.6 (Mantis 7921) extends the IEEE 1364 `begin_keywords/`end_keywords directives with a "VAMS-2023" version specifier. The directives select which identifiers are reserved as keywords, apply to everything that follows — across `include boundaries — until the matching `end_keywords, and may only appear outside a design element.

OpenVAF had no handling for them at all: `begin_keywords fell through to the "unknown macro" path.

Keyword sets

tokens::KeywordSet models the five specifiers the standard requires ("1364-1995", "1364-2001", "1364-2005", "VAMS-2.3", "VAMS-2023") plus OpenVAF's default set, ordered by inclusion.

Every set the standard defines is a subset of what OpenVAF reserves today, so the only table this needs is the IEEE 1364 keyword lists:

  • under a Verilog specifier a word stays reserved iff that revision reserves it;
  • under a Verilog-AMS specifier everything OpenVAF reserves stays reserved.

That keeps the default behaviour bit-for-bit unchanged (no directive ⇒ nothing changes) and makes the Verilog-AMS keywords (analog, discipline, from, string, ground, inf, aliasparam, …), localparam/genvar (1364-2001) and uwire (1364-2005) available as ordinary identifiers when an older specifier is selected.

Two places decide whether a word is a keyword, and both are now version-aware:

  1. LexingTokenKind::to_syntax takes the active set, so released words lex as IDENT.
  2. The reserved-identifier check in syntax::validation, which uses the much larger Annex B list and would otherwise still reject a declaration named sin or discipline. The active set travels on each preprocessor::Token; the tree builder turns that into sorted regions of tree text and validate_name looks the position up.

Without (2) the feature would not actually work — it is what makes the example from §10.6 compile:

`begin_keywords "1364-2005"
module m2(sin);
    input sin;      // OK: `sin` is not a keyword in 1364-2005
endmodule
`end_keywords

Preprocessor

The keyword stack lives on the Processor so it survives `include boundaries; the active set is shared with every per-file Parser through an Rc<LexerState>. Reported as errors:

  • an unknown version specifier (with the list of accepted ones);
  • `end_keywords without a matching `begin_keywords;
  • a `begin_keywords that is never closed;
  • either directive inside a design element. This is tracked with a module/endmodule depth counter that saturates at zero, so it can only ever miss a violation, never invent one.

Drive-by fix

An unexpected compiler directive inside a `define body was diagnosed without consuming the token, so parse_define's while p.before(end) loop spun forever. `begin_keywords in a `define body would have hit exactly that path, so the missing bump() is fixed here.

Deliberately not changed

Words OpenVAF does not reserve today stay unreserved in every set, including "VAMS-2023". sin, abs, expm1, … are shadowable builtins on purpose (compact models such as HiSIMSOTB define their own expm1), and `begin_keywords is not a reason to start rejecting them.

Test plan

  • openvaf/tokens/src/keywords.rs — unit tests: the 1364 sets release the Verilog-AMS keywords, the revision boundaries for localparam/genvar/uwire hold, core keywords stay reserved in every set, and shadowable builtins are reserved in none.
  • openvaf/preprocessor/src/tests.rs — token-stream snapshots for a "1364-2005" region, nested directives (`end_keywords restores the enclosing set, not the default), a directive applying across `include, and a directive in a disabled `ifdef branch; plus diagnostics for an unknown specifier, both unbalanced forms, a directive inside a module, and one inside a `define.
  • openvaf/test_data/syn_ui/begin_keywords.va — the §10.6 example plus Verilog-AMS keywords used as identifiers, compiling with an empty diagnostics log, and ordinary Verilog-AMS code outside the region.
  • openvaf/test_data/syn_ui/begin_keywords_err.va — rendered reports for all four new diagnostics.

Verified locally with LLVM 18:

cargo test -p tokens -p preprocessor -p syntax -p basedb -p hir -p hir_lower -p hir_def -p hir_ty -p parser
RUN_DEV_TESTS=1 cargo test -p basedb -p hir -p hir_lower --test data_tests   # 39/34/33 integration models, all green
cargo build --bin openvaf-r -p openvaf-driver --features llvm18
cargo fmt --all -- --check

🤖 Generated with Claude Code

VAMS-2023 10.6 (Mantis 7921) extends the IEEE 1364 `begin_keywords /
`end_keywords directives with a "VAMS-2023" version specifier. The
directives select which identifiers are reserved as keywords, apply to
everything that follows (across `include boundaries) until the matching
`end_keywords, and may only appear outside a design element. OpenVAF had
no handling for them at all - they fell through to the "unknown macro"
path.

Keyword sets
------------
`tokens::KeywordSet` models the five specifiers the standard requires
("1364-1995", "1364-2001", "1364-2005", "VAMS-2.3", "VAMS-2023") plus
OpenVAF's default set, ordered by inclusion. Every standard set is a
subset of what OpenVAF reserves today, so the only table needed is the
IEEE 1364 keyword lists: under a Verilog specifier a word stays reserved
iff that revision reserves it, and under a Verilog-AMS specifier
everything OpenVAF reserves stays reserved. That keeps the default
behaviour bit-for-bit unchanged and makes the Verilog-AMS keywords
(`analog`, `discipline`, `from`, `string`, `ground`, `inf`, ...),
`localparam`/`genvar` (1364-2001) and `uwire` (1364-2005) available as
ordinary identifiers when an older specifier is selected.

Two places decide whether a word is a keyword, and both are now
version-aware:

- lexing: `TokenKind::to_syntax` takes the active set, so released words
  lex as IDENT.
- the reserved-identifier check in `syntax::validation`, which uses the
  much larger Annex B list and would otherwise still reject a
  declaration named `sin` or `discipline`. The active set travels on
  each `preprocessor::Token`; the tree builder turns that into sorted
  regions of tree text and `validate_name` looks the position up. This
  is what makes the example from 10.6 (`sin` as a port name under
  "1364-2005") actually compile.

Preprocessor
------------
The keyword stack lives on the `Processor` so it survives `include`
boundaries, while the active set is shared with every `Parser` through
an `Rc<LexerState>`. Reported: unknown version specifiers, `end_keywords
without a matching `begin_keywords, a `begin_keywords that is never
closed, and either directive inside a module (tracked with a module
depth counter that saturates at zero, so it can only ever miss a
violation, never invent one).

Also fixes a pre-existing hang: an unexpected compiler directive inside
a `define body was diagnosed without consuming the token, so the
macro-body loop spun forever. `begin_keywords in a `define body would
have hit exactly that path.

Tests:
- tokens: unit tests for the set model (Verilog-AMS keywords released by
  the 1364 sets, revision boundaries for localparam/genvar/uwire, core
  keywords reserved everywhere, shadowable builtins reserved nowhere).
- preprocessor: token-stream snapshots for a "1364-2005" region, nested
  directives, a directive applying across `include, and a directive in a
  disabled `ifdef branch; diagnostics for an unknown specifier, both
  unbalanced forms, a directive inside a module and one inside a
  `define.
- syn_ui/begin_keywords.va: the 10.6 example plus Verilog-AMS keywords
  used as identifiers, compiling without a single diagnostic, and
  ordinary Verilog-AMS code outside the region.
- syn_ui/begin_keywords_err.va: rendered reports for all four
  diagnostics.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@gemini-code-assist

Copy link
Copy Markdown

Caution

The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased.

sai-v-ch added 2 commits July 31, 2026 19:44
Resolves the overlap with OpenVAF#25 (`__FILE__/`__LINE__):
- CompilerDirective gains both pairs of variants.
- parse_macro_token keeps OpenVAF#25's match form, which already contains the
  bump() fix this branch added independently; extended the comment to say
  it covers every directive that is invalid in a `define body.
- Processor carries both the keyword stack/LexerState and expand_seq.
- expand_file_line's Token now sets the new `keywords` field (semantic
  conflict git could not see - the field was added by this branch).
@sai-v-ch
sai-v-ch merged commit 0dcea2f into OpenVAF:mob Aug 1, 2026
11 checks passed
@sai-v-ch
sai-v-ch deleted the vams2023-begin-keywords branch August 1, 2026 03:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant